THREE.Object3D.prototype.toScreenXY = function () {
    // converts 3D position to coords in the div (not screen), based on the viewport and camera (assumed global vars)
    var pos = this.position.clone(), projScreenMat = new THREE.Matrix4();
    projScreenMat.multiply(camera.projectionMatrix, camera.matrixWorldInverse);
    projScreenMat.multiplyVector3(pos);

    return { x :(pos.x + 1) * $(viewportdiv).width() / 2,
             y :(-pos.y + 1) * $(viewportdiv).height() / 2, };
}

THREE.DivSprite = function ( args ) {
        /* Using Vector3, but the Y-value is only used as Z-depth-indicator
        
        */
        
        args = args || { bgpos : {x :    0, y :    0 }, size :  40, rotations : 8};

        this._div;
	    this.name = '';
        this.parent = undefined;
        this.children = {};
        this.children.length = 0;
        this.eulerOrder = 'XYZ';
        this.visible = false;

        this.position = new THREE.Vector3();
        this.rotation = new THREE.Vector3();
        this.scale = new THREE.Vector3( 1, 1, 1 );
        this.drawscale = { x: 32, y: 32 };
        console.log( 'new THREE.DivSprite', args);
        this.image = {
            src : '',
            base_position : new THREE.Vector2(args.bgpos.x, args.bgpos.y),
            size : new THREE.Vector2(args.size, args.size),
            rotations : args.rotations
        }

        this.state = {
            shield : 0,
            moving : 0
        }

}

THREE.DivSprite.prototype = {

	constructor: THREE.DivSprite,

        backgroundPosition : function () {
            var ex = (Math.floor(this.rotation.y*this.image.rotations/(2.0*Math.PI))+2)%this.image.rotations+this.image.rotations*this.state.shield,
                ey = this.state.moving,
                bgx = this.image.base_position.x-ex*this.image.size.x;
                bgy = this.image.base_position.y-ey*this.image.size.y;
           return new THREE.Vector2(bgx,bgy);
        },

        toScreenXY : function () {
            var x = this.position.x*this.drawscale.x+(this.drawscale.x-this.image.size.x),
                y = this.position.z*this.drawscale.y+(this.drawscale.y-this.image.size.y);
            return new THREE.Vector2(x,y);
        },
        
        show : function ( canvas ) {
            this._div = document.createElement("div");
            var bgPos = this.backgroundPosition();
            var rPos = this.toScreenXY();
            this._div.setAttribute('id','sprite');
            this._div.setAttribute('class','sprite');
            //this._div.setAttribute('style','position:relative; left: '+parseInt(rPos.x)+'px; top: '+parseInt(rPos.y)+'px; width: '+parseInt(this.image.size.x)+'px; height: '+parseInt(this.image.size.y)+'px;');
            $(this._div).css('position', 'absolute');
            $(this._div).css('width', parseInt(this.image.size.x-2)+'px');
            $(this._div).css('height', parseInt(this.image.size.y-2)+'px');
            $(this._div).css('top', parseInt(rPos.y)+'px');
            $(this._div).css('left', parseInt(rPos.x)+'px');
            // this._div.setAttribute('style','backgroundPosition: '+parseInt(bgPos.x)+'px '+parseInt(bgPos.y)+'px;');
            var bg = bgPos.x+"px "+bgPos.y+"px";
            $(this._div).css('backgroundPosition', bg);
            canvas.appendChild(this._div);
            this.visible = true;
        },

        hide : function ( canvas ) {
            canvas.removeChild(this._div);
            this.visible = false;
        },

        updatePosition : function () {
            if (this._div && this.visible) {
                var rPos = this.toScreenXY();
                // this._div.setAttribute('style','left: '+parseInt(rPos.x)+'px; top: '+parseInt(rPos.y)+'px;');
                $(this._div).css('top', parseInt(rPos.y)+'px');
                $(this._div).css('left', parseInt(rPos.x)+'px');
            }
        },

        updateImage : function () {
            if (this._div && this.visible) {
                var bgPos = this.backgroundPosition();
                var bg = bgPos.x+"px "+bgPos.y+"px";
                $(this._div).css('backgroundPosition', bg);
                //this._div.setAttribute('style','backgroundPosition: '+parseInt(bgPos.x)+'px '+parseInt(bgPos.y)+'px;');
            }
        }
};

THREE.DivSpriteRenderer = function ( parameters ) {

	console.log( 'THREE.DivSpriteRenderer', THREE.REVISION );

	parameters = parameters || {};

	var _this = this,
	_canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'div' ),
	_canvasWidth, _canvasHeight, _canvasWidthHalf, _canvasHeightHalf,
        _renderData,
        _clipRect = new THREE.Rectangle(),
        _clearRect = new THREE.Rectangle(),
	_drawScale = {
	   x : parameters.drawscale !== undefined ? parameters.drawscale : 1.0,
	   y : parameters.drawscale !== undefined ? parameters.drawscale : 1.0},
	_clearColor = new THREE.Color( 0x000000 );

	this.domElement = _canvas;

	this.autoClear = true;
	this.sortObjects = true;
	this.sortElements = true;

	this.info = {
            sprites : 0

	}

	this.setSize = function ( width, height ) {

		_canvasWidth = width;
		_canvasHeight = height;
		_canvasWidthHalf = Math.floor( _canvasWidth / 2 );
		_canvasHeightHalf = Math.floor( _canvasHeight / 2 );

		_canvas.width = _canvasWidth;
		_canvas.height = _canvasHeight;

		_clipRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
		_clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
	};

	this.setClearColor = function ( color, opacity ) {

		_clearColor.copy( color );
		_clearOpacity = opacity !== undefined ? opacity : 1;
	};

	this.setClearColorHex = function ( hex, opacity ) {

		_clearColor.setHex( hex );
		_clearOpacity = opacity !== undefined ? opacity : 1;
	};

	this.clear = function () {

	};

	this.render = function ( scene, camera ) {


                var renderWalk = function ( object ) {
                    var c,cl

                    if ( object.visible === false ) {
                        return;
                    } else if ( object instanceof THREE.DivSprite ) {
                        renderSprite ( object );
                    }
                    for ( var c = 0, cl = object.children.length; c < cl; c ++ ) {
                        renderWalk( object.children[ c ] );
                    }
                };
                
                renderWalk( scene );
                
                function renderSprite ( sprite ) {
                    sprite.updatePosition ();
                    sprite.updateImage ();
		}

	};
};